#include "operation.h"

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>

extern char * m_usingDatabase;
extern TableListStructPoint tlsp;

extern DatabaseConfigStructPoint m_databaseConfig;

void initDatabase(){
    FILE * configFile = fopen(m_databaseConfig->configPath,"r");
    if(configFile == NULL){
        perror("fopen");
        handleError(CONFIG_FILE_OPEN_ERROR,m_databaseConfig->configPath);
    }
    while(!feof(configFile)){
        char key[50];
        char value[1000];
        fscanf(configFile,"%s %s\n",key,value);
        if(!strcmp(key,"dataDir")){
            m_databaseConfig->m_dataPath = malloc(sizeof(char) * (strlen(value) + 1));
            strcpy(m_databaseConfig->m_dataPath,value);
            break;
        }
    }
    fclose(configFile);
    if(m_databaseConfig->m_dataPath == NULL){
        m_databaseConfig->m_dataPath = "../data";
    }
}

int calTabCnt(int max){
    return (max+1)%m_databaseConfig->tabLength == 0 ? (max+1)/(m_databaseConfig->tabLength):(max+1)%(m_databaseConfig->tabLength) + 1; 
}

void borderPrint(int cnt)
{
	printf("+");
    int tabLength = m_databaseConfig->tabLength;
    for(int i = 1;i < tabLength;i++){
        printf("-");
    }
	while(cnt--)
	{
		for(int i = 0;i < tabLength;i++){
            printf("-");
        }
	}
}

void contentPrint(char * res,int cnt)
{
	int tem;
	printf("| %s\t",res);
	tem = cnt - (strlen(res)+2)/(m_databaseConfig->tabLength);
	while(tem--)
	{
		printf("\t");
	}
}



void _exitDatabase(){}
void freeGlobalVariable(){}


void executeSQL(void * syntaxTree,int type){
    switch(type){
        case CREATEDATABASESQL:
            createDatabase((char *) syntaxTree);
            break;
    }
    printf("LiSQL>");
}


void freeStruct(enum STRUCT type,void * root){
    switch(type){
        case TABLELIST:
            TableListStructPoint tmp  = (TableListStructPoint)root;
            TableListStructPoint next;
            next = tmp->next;
            while(tmp != NULL){
                next = tmp->next;
                free(tmp);
                tmp = next;
            }
    }
}

void writebackTableList(){
    
}

TableListStructPoint readTableList(){
    char * m_tableListFile = strpathcat(m_usingDatabase,"tableList.sdb");
    FILE * fp = fopen(m_tableListFile,"r");
    if(fp == NULL){
        handleError(CONFIG_TABLE_CREATE_ERROR,m_tableListFile);
        free(m_tableListFile);
        return NULL;
    }   
    char buffer[128];
    TableListStructPoint head,now;
    head = NULL;
    while(!feof(fp)){
        fscanf(fp,"%s",buffer);
        if(head == NULL){
            head = (TableListStructPoint)malloc(sizeof(TableListStruct));
            now = head;
        }else{
            now->next = (TableListStructPoint)malloc(sizeof(TableListStruct));
            now = now->next;
        }
        strcpy(now->name,buffer);
        now->next = NULL;
    }
    fclose(fp);
    return head;
}


// use database;
void useDatabase(char * dbname){
    char * tmp = m_usingDatabase;
    m_usingDatabase  = strpathcat(m_databaseConfig->m_dataPath,dbname);
    
    // Judge the database exists.
    if(access(m_usingDatabase,F_OK) != 0){
        handleError(DATABASE_NOT_EXIST_ERROR,dbname);
        free(m_usingDatabase);
        m_usingDatabase = tmp;
        return;
    }

    if(tlsp == NULL){
        freeStruct(TABLELIST,tlsp);

    }

    if(tmp != NULL){
        free(m_usingDatabase);
    }
    return;
}

// create database dbname;
void createDatabase(char *dbname){
    char * m_dbDir = strpathcat(m_databaseConfig->m_dataPath,dbname);
    // The creator has the database primission.
    if(mkdir(m_dbDir,0600) == -1){
        perror("mkdir");
        handleError(CREATE_DATABASE_ERROR,dbname);
        free(m_dbDir);
        return;
    }
    char * m_tableListFile = strpathcat(m_dbDir,"tableList.sdb"); 
    FILE * fp = fopen(m_tableListFile,"w");
    if(fp == NULL){
        handleError(CONFIG_TABLE_CREATE_ERROR,m_usingDatabase);
    }

    fclose(fp);
    free(m_dbDir);
    free(m_tableListFile);
};

int printTableItem(TableListStructPoint tmp,int max){
    max = max >= strlen(tmp->name) ? max : strlen(tmp->name);
    if(tmp->next == NULL){
        int cnt = calTabCnt(max);
        borderPrint(cnt);
        printf("+\n");

        contentPrint("tables",cnt);
        printf("|\n");

        borderPrint(cnt);
        printf("+\n");
    
    }else{
        max = printTableItem(tmp->next,max);
        contentPrint(tmp->name,calTabCnt(max));
        printf("|\n");
    }
    return max;
}

void showTables(){
    printTableItem(tlsp,0);
}


void handleError(enum EXECEUTERROR error,void * data){
    switch(error){
        case CONFIG_FILE_OPEN_ERROR:
            printf("error: Can not open config file '%s'!\n",(char *)data);break;
        case CREATE_DATABASE_ERROR:
            printf("error: Fail to create database in path '%s'!\n",(char *)data);break;
        case DATABASE_NOT_EXIST_ERROR:
            printf("error: Database '%s' does not exist !",(char *)data);
        case CONFIG_TABLE_CREATE_ERROR:
            printf("error: Can not create tableList.sdb in database '%s'!",(char *)data);
    }
}

char * strpathcat(char * prefix,char * other){
    char * result = (char *)malloc(sizeof(char) * (strlen(prefix) + strlen(other) + 2));
    strcpy(result,prefix);
    strcpy(result,"/");
    strcat(result,other);
    return result;
}


